﻿<script setup lang="ts">
import * as echarts from 'echarts'
import type { EChartsOption, SeriesOption, ECharts } from 'echarts'
import { debounce } from 'lodash-es'
import { propTypes } from '@/utils/propTypes'
import { PropType } from 'vue'
import { isString } from '@/utils/is'
import { storeToRefs } from 'pinia'
import { useSystemConfigStore } from '@/store/storage/systemConfigStore'
import { baseChartOptions, axisOptions } from '@/hooks/charts/baseChartOptions'
import { deepMerge } from '@/utils'
import { templateRef, useResizeObserver, useDebounceFn } from '@vueuse/core'
import XEUtils from 'xe-utils'
import { worldGeo } from '@/hooks/charts/mapCharts/map/world'
import { worldZhGeo } from '@/hooks/charts/mapCharts/map/worldZH'
import { chinaGeo } from '@/hooks/charts/mapCharts/map/china'
import { chinaWorldGeo } from '@/hooks/charts/mapCharts/map/chinaWorld'
const systemConfigStore = useSystemConfigStore()
const { systemConfig } = storeToRefs(systemConfigStore)

const props = defineProps({
  options: {
    type: Object as PropType<EChartsOption>,
    required: true
  },
  customSeriesOptions: {
    type: Object as PropType<SeriesOption>
  },
  map: {
    type: String
  },
  width: propTypes.oneOfType([Number, String]).def(''),
  height: propTypes.oneOfType([Number, String]).def('500px')
})

const options = computed(() => {
  // let newOptions: any = props.options
  const newOptions = deepMerge(baseChartOptions(systemConfig), props.options)
  if (!props.map) {
    if (newOptions.xAxis) {
      if (XEUtils.isArray(newOptions.xAxis)) {
        for (let i = 0; i < newOptions.xAxis.length; i++) {
          newOptions.xAxis[i] = deepMerge(newOptions.xAxis[i], axisOptions(systemConfig))
        }
      } else {
        newOptions.xAxis = deepMerge(newOptions.xAxis, axisOptions(systemConfig))
      }
    } else {
      newOptions.xAxis = axisOptions(systemConfig)
    }
    if (newOptions.yAxis) {
      if (XEUtils.isArray(newOptions.yAxis)) {
        for (let i = 0; i < newOptions.yAxis.length; i++) {
          newOptions.yAxis[i] = deepMerge(newOptions.yAxis[i], axisOptions(systemConfig))
        }
      } else {
        newOptions.yAxis = deepMerge(newOptions.yAxis, axisOptions(systemConfig))
      }
    } else {
      newOptions.yAxis = axisOptions(systemConfig)
    }
  }
  if (props.customSeriesOptions) {
    newOptions.series.forEach((item, index) => {
      deepMerge(item, props.customSeriesOptions[index])
    })
  }
  return newOptions
})

const elRef = ref<ElRef>()

let echartRef: Nullable<ECharts> = null

const styles = computed(() => {
  const width = isString(props.width) ? props.width : `${props.width}px`
  const height = isString(props.height) ? props.height : `${props.height}px`

  return {
    width,
    height
  }
})

const initChart = () => {
  if (unref(elRef) && props.options) {
    if (props.map) {
      if (props.map === 'china') { // 中国地图
        echarts.registerMap('china', chinaGeo())
      } else if (props.map === 'worldZH') { // 世界地图-中国为中心
        echarts.registerMap('worldZH', worldZhGeo())
      } else if (props.map === 'world') { // 世界地图-欧洲为中心
        echarts.registerMap('world', worldGeo())
      } else { // 中国地图-带周边国家边界
        echarts.registerMap('chinaWorld', chinaWorldGeo())
      }
    }
    echartRef = echarts.init(unref(elRef) as HTMLElement)
    echartRef?.setOption(unref(options))
  }
}

watch(
  () => options.value,
  (options) => {
    if (echartRef) {
      echartRef?.setOption(options)
    }
  },
  {
    deep: true
  }
)

const resizeHandler = debounce(() => {
  if (echartRef) {
    echartRef.resize()
  }
}, 100)

const elRefDom = templateRef<HTMLElement | null>('elRef', null)
// 监听元素尺寸变化
useResizeObserver(
  elRefDom,
  useDebounceFn(() => {
    resizeHandler()
  }, 200)
)

onMounted(() => {
  initChart()

  window.addEventListener('resize', resizeHandler)
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', resizeHandler)
})

onActivated(() => {
  if (echartRef) {
    echartRef.resize()
  }
})
</script>

<template>
  <div ref="elRef" :style="styles"></div>
</template>
